#include "Pch.h"

#include "SphericalSamplers.h"
#include "../HaltonSequence.h"

#include <vector>
#include <cstdlib>
#include <cmath>
#include <limits>

namespace IS
{

/*----------------------------------------------------------------------------*/
void RandomSphericalSampler::generateN(size_t n, std::vector<Vec3f>& outs)
{
	if(0 == n) return;

	outs.clear();

	do
	{
		double x = double(rand()) / double(RAND_MAX);
		double y = double(rand()) / double(RAND_MAX);

		x = x * 2 - 1;
		y = y * 2 - 1;

		if(x*x + y*y > 1) continue;

		double z = sqrt(1.0 - x*x - y*y);

		double s = double(rand()) / double(RAND_MAX);
		if(s < 0.5) z = -z;

		outs.push_back(Vec3f((float)x, (float)y, (float)z));
	}
	while(outs.size() < n);
}

/*----------------------------------------------------------------------------*/
void RandomSphericalSamplerUniform::generateN(size_t n, std::vector<Vec3f>& outs)
{
	if(0 == n) return;

	outs.clear();

	do
	{
        Vec3f s;
        do {
		    double x = double(rand()) / double(RAND_MAX);
		    double y = double(rand()) / double(RAND_MAX);
		    double z = double(rand()) / double(RAND_MAX);

		    x = x * 2 - 1;
		    y = y * 2 - 1;
		    z = z * 2 - 1;

		    s = Vec3f((float)x, (float)y, (float)z);
        } while(s.length() > 1);

//		s.normalize();
		outs.push_back(s);
	}
	while(outs.size() < n);
}

/*----------------------------------------------------------------------------*/
class HaltonSphericalSampler::Impl
{
public:
	HaltonSequence<double> halton2;
	HaltonSequence<double> halton3;
	HaltonSequence<double> halton5;

	Impl() : halton2(2), halton3(3), halton5(5)
	{
	}
};

HaltonSphericalSampler::HaltonSphericalSampler()
: mImpl(new Impl)
{
}

HaltonSphericalSampler::~HaltonSphericalSampler()
{
	delete mImpl;
}

void HaltonSphericalSampler::generateN(size_t n, std::vector<Vec3f>& outs)
{
	if(0 == n) return;

	outs.clear();

	do
	{
		double x = mImpl->halton2.getNext();
		double y = mImpl->halton3.getNext();
		double z = mImpl->halton5.getNext();

		x = x * 2 - 1;
		y = y * 2 - 1;
		z = z * 2 - 1;

		Vec3f s((float)x, (float)y, (float)z);
		s.normalize();

		outs.push_back(s);
	}
	while(outs.size() < n);
}

}	// namespace IS